package com.wjk.cms.controller;

import com.alibaba.fastjson.JSONObject;
import com.wjk.cms.common.AppType;
import com.wjk.cms.common.AuthControllerHelper;
import com.wjk.cms.common.Result;

import com.wjk.cms.pojo.Card;
import com.wjk.cms.pojo.Order;
import com.wjk.cms.pojo.User;

import com.wjk.cms.service.*;
import com.wjk.cms.util.EncodingUtil;
import com.wjk.cms.util.HttpUtil;
import com.wjk.cms.util.wx.WxConfig;
import com.wjk.cms.util.wx.WxGzhJsSdkSign;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import com.wjk.cms.util.CommonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.AlgorithmParameters;
import java.security.Security;
import java.util.*;

@Slf4j
@RestController
@RequestMapping("/auth")
public class AuthController extends UnauthenticatedController {

    @Autowired
    private AuthControllerHelper authControllerHelper;



    @Autowired
    private UserService userService;

    @Autowired
    private VerificationCodeService verificationCodeService;


    @Autowired
    private WxGzhService wxGzhService;


    @Autowired
    private WxXcxService wxXcxService;

    @Autowired
    private CardService cardService;

    @Autowired
    private OrderService orderService;


    @Transactional
    @PostMapping("/wxxcxLogin")
    public Result wxxcxLogin(
            HttpServletRequest request,
            @RequestParam(value = "jsCode", required = false) String jsCode // 有效期内code
    ) throws IOException {
        String appid =WxConfig.APP_ID();

        JSONObject wxData = HttpUtil.getJson("https://api.weixin.qq.com/sns/jscode2session?appid=" + appid + "&secret=" + WxConfig.APP_SECRET() + "&grant_type=authorization_code&js_code=" + jsCode);
        log.info(wxData.toJSONString());
        String openid = wxData.getString("openid");
        String unionId = wxData.getString("unionid");
        String session_key = wxData.getString("session_key");
        return Result.ok().add("openid",openid).add("unionid",unionId);
    }
    /**
     * 微信登录
     */
    @Transactional
    @PostMapping("/wx-login")
    public Result wxLogin(
            HttpServletRequest request,
           
            @RequestParam(value = "jsCode", required = false) String jsCode, // 有效期内code
            @RequestParam(value = "invitationCode", required = false) String invitationCode// 邀请码
           
    ) {
        String channel = getChannel();
        String appType = AppType.get();

        log.info("请求参数 - /auth/wx-login\n"
                + "[Headers]\n"
                + "channel: " + channel + "\n"
                + "appType: " + appType + "\n"
              
                + "[Body]" + "\n"
               
                + "jsCode: " + jsCode + "\n"
                + "invitationCode: " + invitationCode);

        
        jsCode = clearUndefined(jsCode);
        invitationCode = clearUndefined(invitationCode);
       
        String openid = "";
        String unionId = "";
        String headimgurl = "";
        String nickname = "";
        if ( StringUtils.isNotEmpty(jsCode)) {
            try {
                String appid = WxConfig.GZH_APP_ID();
                log.info("appid:"+appid +"==secrect:"+WxConfig.GZH_APP_SECRET());
                JSONObject step2Json = HttpUtil.getJson("https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appid + "&secret=" + WxConfig.GZH_APP_SECRET() + "&code=" + jsCode + "&grant_type=authorization_code");
                log.info(step2Json.toJSONString());
                JSONObject wxData = HttpUtil.getJson("https://api.weixin.qq.com/sns/userinfo?access_token=" + step2Json.getString("access_token") + "&openid=" + step2Json.getString("openid") + "&lang=zh_CN");
                log.info(wxData.toJSONString());
                openid = wxData.getString("openid");
                unionId = wxData.getString("unionid");
              
                nickname = wxData.getString("nickname");
                headimgurl = wxData.getString("headimgurl");
            } catch (Exception e) {
                log.error("获取unionid遇到错误 - " + e.getMessage(), e);
            }
        }

        if (StringUtils.isEmpty(unionId)) {
            return Result.error("unionId为空");
        }
        User user = userService.getByUnionid(unionId);
        if (user == null) {
            return Result.error(1001, "用户不存在") // 前台根据1001来判断是否需要进行绑定手机号的操作
                    .add("openid", openid)
                    .add("unionid", unionId)
                    .add("headimgurl", headimgurl)
                    .add("nickname", nickname);
        }

        if (StringUtils.isNotEmpty(nickname) && !StringUtils.equals(nickname, user.getNickname())) {
            user.setNickname(nickname);
            userService.save(user);
        }
        if (StringUtils.isNotEmpty(headimgurl) && !StringUtils.equals(headimgurl, user.getHeadPortrait())) {
            user.setHeadPortrait(headimgurl);
            userService.save(user);
        }

      if (AppType.WX_XCX.equals(appType)) {
            if (StringUtils.isEmpty(user.getWxXcxOpenid()) && StringUtils.isNotEmpty(openid)) {
                user.setWxXcxOpenid(openid);
                userService.save(user);
            }
        }



        return Result.ok()
                .add("token", CommonUtil.getToken(user))
                .add("user", user);
    }

    /**
     * app登录
     */



    @Transactional
    @PostMapping("/wxxcx-login")
    public Result wxxcxLogin(
            HttpServletRequest request,
            @RequestParam(value = "jsCode", required = false) String jsCode, // 有效期内code
            @RequestParam(value = "invitationCode", required = false) String invitationCode, // 邀请码
            @RequestParam(value = "encryptedData", required = false) String encryptedData, // 昵称等数据
            @RequestParam(value = "iv", required = false) String iv,
            @RequestParam(value = "nickname", required = false) String nickname, // 昵称
            @RequestParam(value = "headPortrait", required = false) String headPortrait // 头像

    ) {
        String channel = getChannel();
        String appType = AppType.get();

        log.info("请求参数 - /auth/wxxcx-login\n"
                + "[Headers]\n"
                + "channel: " + channel + "\n"
                + "appType: " + appType + "\n"

                + "[Body]" + "\n"
                + "encryptedData: " + encryptedData + "\n"
                + "iv: " + iv + "\n"
                + "jsCode: " + jsCode + "\n"
                + "invitationCode: " + invitationCode

               );

        String unionId = "";
        String openid = "";
        String onickname = "";
        String oheadPortrait = "";
        String phone = "";
        String session_key = "";
        jsCode = clearUndefined(jsCode);



        if (StringUtils.isEmpty(unionId) && StringUtils.isNotEmpty(jsCode)) {
            try {
                String appid =WxConfig.APP_ID();

                JSONObject wxData = HttpUtil.getJson("https://api.weixin.qq.com/sns/jscode2session?appid=" + appid + "&secret=" + WxConfig.APP_SECRET() + "&grant_type=authorization_code&js_code=" + jsCode);
                log.info(wxData.toJSONString());
                openid = wxData.getString("openid");
                unionId = wxData.getString("unionid");
                session_key = wxData.getString("session_key");
                String decrypted = decryptWxData(encryptedData, session_key, iv);
                log.info("decrypted:"+decrypted);
                JSONObject infoData = JSONObject.parseObject(decrypted);

                if( infoData.containsKey("nickName")){
                    onickname = infoData.getString("nickName");
                }
                if( infoData.containsKey("avatarUrl")){
                    oheadPortrait = infoData.getString("avatarUrl");
                }

                if(StringUtils.isBlank(onickname) && StringUtils.isNotBlank(nickname)){
                    onickname = nickname;
                }
                if(StringUtils.isBlank(oheadPortrait) && StringUtils.isNotBlank(headPortrait)){
                    oheadPortrait = headPortrait;
                }
                if(StringUtils.isBlank(unionId)){

                    unionId = infoData.getString("unionId");
                }
                if(StringUtils.isBlank(unionId)){
                    unionId = openid;
                }

                log.info("unionId:"+unionId);

            } catch (Exception e) {
                log.error("获取unionid遇到错误 - " + e.getMessage(), e);
            }
        }

        if (StringUtils.isEmpty(unionId)) {
            return Result.error("unionId为空");
        }
        User user = userService.getByUnionid(unionId);

        if (user == null) {
            return Result.error(1001, "用户不存在")
                    .add("session_key",session_key)
                    .add("openid", openid)
                    .add("unionid", unionId)
                    .add("headPortrait", oheadPortrait)
                    .add("nickname", onickname);
        }


        if(StringUtils.isNotBlank(nickname)){
            user.setNickname(nickname);
        }
        if(StringUtils.isNotBlank(headPortrait)){
            user.setHeadPortrait(headPortrait);
        }

        if (StringUtils.isEmpty(user.getWxXcxOpenid()) && StringUtils.isNotEmpty(openid)) {
            user.setWxXcxOpenid(openid);
        }
        userService.save(user);


        Result result = authControllerHelper.loadUserInfo(request, Result.ok(), user);
        return result;
    }

    /**
     * 绑定手机号
     */
    @Transactional
    @PostMapping("/bind-phone")
    public Result bindPhone(
            HttpServletRequest request,
            @RequestParam(value = "encryptedData", required = false) String encryptedData, //手机数据
            @RequestParam(value = "iv", required = false) String iv, //
            @RequestParam("session_key") String session_key, //
            @RequestParam("unionId") String unionId, // 微信unionId
            @RequestParam(value = "openid", required = false) String openid, // 微信openid
            @RequestParam("nickname") String nickname, // 昵称
            @RequestParam("invitationCode") String invitationCode, // 推广码
            @RequestParam("headPortrait") String headPortrait // 头像
    ) {
        String channel = getChannel();
        String appType = AppType.get(AppType.WX_XCX);


        log.info("请求参数 - /auth/bind-phone\n"
                + "[Headers]\n"
                + "channel: " + channel + "\n"
                + "appType: " + appType + "\n"

                + "[Body]" + "\n"
                +"encryptedData2: " + encryptedData + "\n"
                + "iv2: " + iv + "\n"
                + "session_key: " + session_key + "\n"

                + "unionId: " + unionId + "\n"
                + "openid: " + openid + "\n"
                + "invitationCode: " + invitationCode + "\n"
                + "headPortrait: " + headPortrait);

        String phone="";
        String phoneObject = decryptWxData(encryptedData, session_key, iv);
        log.info("phoneData:"+phoneObject);
        JSONObject phoneData = JSONObject.parseObject(phoneObject);
        if(phoneData.containsKey("phoneNumber")){
            phone = phoneData.getString("phoneNumber");
        }

        unionId = clearUndefined(unionId);
        openid = clearUndefined(openid);
        nickname = clearUndefined(nickname);
        invitationCode = clearUndefined(invitationCode);
        headPortrait = clearUndefined(headPortrait);


        if (StringUtils.isEmpty(phone)) {
            return Result.error("phone为空");
        }
        if (StringUtils.isEmpty(unionId)) {
            return Result.error("unionId为空");
        }

        User user = userService.getByPhone(phone);
        if (user == null) {
            user = authControllerHelper.registerUser(invitationCode, phone, unionId, nickname, headPortrait);

        } else {
            if (!StringUtils.isEmpty(unionId)) {
                
                user.setUnionid(unionId);
            }
            if (!StringUtils.isEmpty(nickname)) {
                user.setNickname(CommonUtil.cleanUtf8Mb4Characters(nickname));
            }
            if (!StringUtils.isEmpty(headPortrait)) {
                user.setHeadPortrait(headPortrait);
            }
            if (!StringUtils.isEmpty(phone)) {
                user.setPhone(phone);
            }
            userService.save(user);
        }

    if (AppType.WX_XCX.equals(appType)) {
            if (StringUtils.isEmpty(user.getWxXcxOpenid()) && StringUtils.isNotEmpty(openid)) {
                user.setWxXcxOpenid(openid);
                userService.save(user);
            }
        }



        Result result = authControllerHelper.loadUserInfo(request, Result.ok(), user);


        return result;

    }




    /**
     * 微信JS-SDK配置接口(对接航伙伴公众号)
     */
    @PostMapping("/wx-config")
    public Result wxConfig(
            @RequestParam("url") String url
    ) {

        String channel = getChannel();
        log.info("channel:"+channel);
        String decodedUrl = EncodingUtil.decodeURIComponent(url);
        Map<String, String> config = WxGzhJsSdkSign.sign(wxGzhService.getJsApiTicket(), decodedUrl);
        config.put("appId", WxConfig.GZH_APP_ID());
        log.info(config + "");
        return Result.ok().add("data", config);
    }

    /**
     * 渠道商登录
     */
    @Transactional
    @PostMapping("/user-login")
    public Result userLogin(
            HttpServletRequest request,
            @RequestParam("phone") String phone, // 手机号
            @RequestParam("password") String password,
            @RequestParam(value = "openid",required = false) String openid
    ) throws IOException {
        String channel = getChannel();
        String appType = AppType.get();


        log.info("请求参数 - /auth/user-login\n"
                + "[Headers]\n"
                + "channel: " + channel + "\n"
                + "appType: " + appType + "\n"

                + "[Body]" + "\n"
                + "phone: " + phone + "\n"
                + "password: " + password + "\n" +
                        "openid:"+openid
                );



//        verificationCodeService.verify(phone, code);

        User user = userService.getByPhone(phone);
        if( user!=null && password.equals(user.getPassword()) && user.getStatus().equals("1")) {

            if(StringUtils.isNotBlank(openid) && StringUtils.isBlank(user.getWxXcxOpenid())){

//                User byWxXcxOpenid = userService.getByWxXcxOpenid(openid);
//                if(byWxXcxOpenid!=null){
//                    return Result.error("一个微信号只能使用一个身份登录，该微信已经有其它身份！");
//                }
                user.setWxXcxOpenid(openid);
                userService.save(user);
            }
            return authControllerHelper.loadUserInfo(request, Result.ok(), user);
        }else {
            return Result.error("手机或者密码错误");
        }
    }

    /*** 
     * @description: 经销商登录
     * @param: [request, phone, password] 
     * @return: com.wjk.cms.common.Result
     * @author WUGN
     * @date: 2021/10/22 16:59
     */
    @Transactional
    @PostMapping("/sellerlogin")
    public Result sellerLogin(
            HttpServletRequest request,
            @RequestParam("phone") String phone, // 手机号
            @RequestParam("password") String password
    ) throws IOException {
        String channel = getChannel();
        String appType = AppType.get();


        log.info("请求参数 - /auth/phone-register\n"
                + "[Headers]\n"
                + "channel: " + channel + "\n"
                + "appType: " + appType + "\n"

                + "[Body]" + "\n"
                + "phone: " + phone + "\n"
                + "password: " + password + "\n"
        );



//        verificationCodeService.verify(phone, code);

        User user = userService.getByPhone(phone);
        if(user!=null && password.equals(user.getPassword()) && user.getStatus().equals("1") && user.getType().equals("2")) {

            return authControllerHelper.loadUserInfo(request, Result.ok(), user);
        }else {
            return Result.error("手机或者密码错误");
        }
    }

    @Transactional
    @PostMapping("/cardLogin")
    public Result cardLogin(
            HttpServletRequest request,
            @RequestParam("code") String code, // 卡号
            @RequestParam("password") String password,
            @RequestParam(value = "openid",required = false) String openid
    ) throws IOException {


        log.info("请求参数 - /auth/cardLogin\n"
                + "[Headers]\n"
                + "[Body]" + "\n"
                + "code: " + code + "\n"
                + "password: " + password + "\n" +
                "openid:"+openid
        );



//        verificationCodeService.verify(phone, code);

        Card card = cardService.getByCode(code);
        if(card==null){
            return Result.error("卡不存在");
        }
        if(card.getStatus()<2){
            return Result.error("卡未激活,请及时联系销售人员进行激活！");
        }
        if(password.equals(card.getPassword())  ) {

            User user = null;
            if(StringUtils.isNotBlank(openid)){
                user = userService.getByTypeAndWxXcxOpenid("0",openid);
            }
            if(user==null){
                user = new User();
                user.setType("0");
                user.setPassword(card.getPassword());
                user.setStatus("1");
                user.setWxXcxOpenid(openid);
                userService.save(user);
            }
//            else if(!user.getType().equals("0")){
//                return Result.error("一个微信号只能使用一个身份登录，该微信已经有其它身份！");
//            }
            card.setCustomerId(user.getId());
            cardService.save(card);
            Order order = orderService.getByCardId(card.getId());
            if(order !=null ) {
                order.setCustomerId(user.getId());
                orderService.save(order);
            }
            Result res = authControllerHelper.loadUserInfo(request, Result.ok(), user);
            res.add("card",card);
            return res;
        }else {
            return Result.error("密码错误");
        }
    }









    @PostMapping("/getWxXcxCode")
    public Result getWxXcxCode(
            @RequestParam(value = "userCode", required = false) String userCode,
            @RequestParam(value = "cdkey", required = false) String cdkey,
            @RequestParam(value = "type", required = false,defaultValue = "1") String type
    ){
        String channel = getChannel();
        BufferedImage unlimited = wxXcxService.getUnlimited(userCode,channel);
        if(unlimited==null){
            return Result.error("生成失败");
        }
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        try {
            ImageIO.write(unlimited, "png", stream);
            BASE64Encoder encoder = new BASE64Encoder();
            String base64 = encoder.encode(stream.toByteArray());
            base64 = base64.replaceAll("\n", "").replaceAll("\r", "");
            return Result.ok().add("data","data:image/png;base64,"+ base64);
        } catch (IOException e) {
            e.printStackTrace();
            return Result.error("生成失败");
        }

    }



    public static String decryptWxData(String encryptedData, String sessionKey, String iv) {
        try {
            // 被加密的数据
            byte[] dataByte = Base64.decode(encryptedData);
            // 加密秘钥
            byte[] keyByte = Base64.decode(sessionKey);
            // 偏移量
            byte[] ivByte = Base64.decode(iv);
            // 如果密钥不足16位，那么就补足.  这个if 中的内容很重要
            int base = 16;
            if (keyByte.length % base != 0) {
                int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
                byte[] temp = new byte[groups * base];
                Arrays.fill(temp, (byte) 0);
                System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
                keyByte = temp;
            }
            // 初始化
            Security.addProvider(new BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
            parameters.init(new IvParameterSpec(ivByte));
            cipher.init(Cipher.DECRYPT_MODE, spec, parameters); // 初始化
            byte[] resultByte = cipher.doFinal(dataByte);
            if (resultByte != null && resultByte.length > 0) {
                return new String(resultByte, "UTF-8");
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }


    @PostMapping("/test")
    public Result test(){
        User user = authControllerHelper.registerUser("hlt","CDE1592810820438", "13290249271", "o08sc1ORrH9b9WkxgwQhiM3lHPtg", "app小程序公众号开发18615643568", "https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTIUKCzLFktSYEQ24ibVU5umlJQgZnpryJO2h50vSDoMLzMKIMZobXIXEHbsKj0wDukmoCrO1zNf5yg/132");
        return  Result.ok().add("data",user);
    }

    @PostMapping("/baiduAi")
    public Result baiduAi(
            @RequestParam(value = "image", required = true) String image,
            @RequestParam(value = "method", required = true,defaultValue = "vehicle_license") String method,
            @RequestParam(value = "id_card_side", required = false,defaultValue = "front") String id_card_side
    ){
        log.info("baiduAi:\n method:"+method);
        String url = "https://aip.baidubce.com/oauth/2.0/token";
        HttpUtil httpUtil = new HttpUtil();
        CloseableHttpClient webClient = httpUtil.createSSLClientDefault(false);
        long systime = System.currentTimeMillis();
        Map<String, String> params = new HashMap<>();

        List<NameValuePair> query_params = new ArrayList<NameValuePair>();
        query_params.add(new BasicNameValuePair("grant_type", "client_credentials"));
        query_params.add(new BasicNameValuePair("client_id", "kb1cppPS0eFAzu0ofEOlQx0e"));
        query_params.add(new BasicNameValuePair("client_secret", "mN22QMHXVNfy0qNFtgBLR5usIA9mhhR4"));


        Map<String, Object> secBody = null;
        try {
            secBody = httpUtil.sendHttpPost(webClient, url, null, query_params, false, systime);
            HttpEntity secEntity = (HttpEntity) secBody.get("httpEntity");
            String secBodyStr = EntityUtils.toString(secEntity);
            JSONObject o = JSONObject.parseObject(secBodyStr);
            String token = o.getString("access_token");
            System.out.println(token);

            query_params = new ArrayList<NameValuePair>();
            query_params.add(new BasicNameValuePair("image", image));
            query_params.add(new BasicNameValuePair("detect_direction", "true"));
            query_params.add(new BasicNameValuePair("access_token", token));
            query_params.add(new BasicNameValuePair("detect_language", "true"));
            if(method.equals("idcard")){
                query_params.add(new BasicNameValuePair("id_card_side", id_card_side));
            }

            String licenseUrl = "https://aip.baidubce.com/rest/2.0/ocr/v1/"+method;
            secBody = httpUtil.sendHttpPost(webClient, licenseUrl, null, query_params, false, systime);
            secEntity = (HttpEntity) secBody.get("httpEntity");
            secBodyStr = EntityUtils.toString(secEntity);
            JSONObject object = JSONObject.parseObject(secBodyStr);
            System.out.println(secBodyStr);
            JSONObject license = object.getJSONObject("words_result");
            System.out.println(license);
            if(license.containsKey("单位名称")){
                JSONObject nameObj = license.getJSONObject("单位名称");
                System.out.println(nameObj.getString("words"));
            }
            return Result.ok().add("data",license);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("识别报错");
        }


    }





    public static void main(String[] args) throws IOException {
//        AuthController authController = new AuthController();
//        File f = new File("C:\\Users\\l\\Desktop\\图片\\id.jpg");
//        BufferedImage read = ImageIO.read(f);
//        ByteArrayOutputStream stream = new ByteArrayOutputStream();
//
//        ImageIO.write(read, "jpg", stream);
//        BASE64Encoder encoder = new BASE64Encoder();
//        String base64 = encoder.encode(stream.toByteArray());
//        base64 = base64.replaceAll("\n", "").replaceAll("\r", "");
//        authController.baiduAi(base64,"idcard","front");
        String appid="wx38e485efd4088e13";
        String secret = "e89d204e3e2d3a56d8d7dab93603a20f";
        String jsCode = "0717n8ll2FZ9874KwVol2yFol427n8lS";

        JSONObject wxData = HttpUtil.getJson("https://api.weixin.qq.com/sns/jscode2session?appid=" + appid + "&secret=" +secret + "&grant_type=authorization_code&js_code=" + jsCode);
        log.info(wxData.toJSONString());
       String  openid = wxData.getString("openid");
       log.info(openid);
    }

}
